#include <extractGraph/extractGraph.h>
#include <multipleImage/multipleImage.h>
#include <opencv2/xfeatures2d/nonfree.hpp>
#include <opencv2/opencv.hpp>
#include <unordered_map>

using namespace xfeatures2d;

#define DBUG

UnderTestElectronics underTestEle(imread("../../resource/image/circult/image3.jpg"));
TemplateDataRead dataRead(TEMPLATE_KEYPOINTS_DIR, TEMPLATE_DESCRIPTOR_DIR);
TemplateElectronics templateEle(dataRead.fKeyPoints,
                                dataRead.fDescriptor,
                                TEMPLATE_IMG_DIR);
//取待检测图片的一个器件，对所有样本库文件进行检测
//一对一检测生成vector<DMatch>数据，一对多生成vector<vector<DMatch>>数据
//返回与当前器件最匹配的样本编号和相匹配点的数目
Vec2i getGoodMatchUseKnn(Mat underTestCellDescriptor)  //使用最近邻knn算法
{
    Vec2i bestMatchInfo(0 ,0);  //最匹配信息 包含最匹配样本和匹配点数目
    vector< vector<vector<DMatch>> > matchPointVector(templateEle.count);
    vector<vector<DMatch>> goodMatchPoints(templateEle.count);

    for (int eachTemplate = 0; eachTemplate < templateEle.count; eachTemplate++)
    {
        FlannBasedMatcher matcher;
        vector<Mat> trainDescriptor( 1, templateEle.descriptor[eachTemplate] );
        matcher.add( trainDescriptor );
        matcher.train();
        //knn 使用underTestCellDescriptor计算eachTamplate的matchPoint
        matcher.knnMatch( underTestCellDescriptor, matchPointVector[eachTemplate], 2);
        for (size_t eachPoints=0; eachPoints < matchPointVector[eachTemplate].size(); eachPoints++)
        {
            /*matchPointVector[eachTempate][eachPoints]为vector<DMatch>类型，
             * 即每个匹配点的信息表述为vector<DMatch>类型，eachPoint->vector<DMatch>
             * 下面比较的是每个匹配点的DMatch信息，即DMatch0和DMatch1的信息
            */
            if (matchPointVector[eachTemplate][eachPoints][0].distance <
                   0.5 * matchPointVector[eachTemplate][eachPoints][1].distance)
            {
                cout << "\t" << matchPointVector[eachTemplate][eachPoints][0].distance
                     << " " << matchPointVector[eachTemplate][eachPoints][1].distance << endl;
                goodMatchPoints[eachTemplate].push_back(
                            matchPointVector[eachTemplate][eachPoints][0]);
            }
        }
#ifdef DBUG
        cout << eachTemplate << " " << goodMatchPoints[eachTemplate].size() << " " << templateEle.allName[eachTemplate] << endl;
#endif
        //完成对一个模板的优秀特征点提取
        if ( (int)goodMatchPoints[eachTemplate].size() > bestMatchInfo[1] )
        {
            bestMatchInfo[0] = eachTemplate;
            bestMatchInfo[1] = goodMatchPoints[eachTemplate].size();
        }
    }
    cout << "一个元件匹配结束.." << endl;

    return bestMatchInfo;
}

Vec2i getGoodMatchUseCustom(Mat underTestCellDescriptor)  //使用最优匹配算法
{
    Vec2i bestMatchInfo(0 ,0);  //最匹配信息 包含最匹配样本和匹配点数目
    vector<vector<DMatch>> matchPointVector(templateEle.count);
    vector<vector<DMatch>> goodMatchPoints(templateEle.count);

    for (int eachTemplate = 0; eachTemplate < templateEle.count; eachTemplate++)
    {
        FlannBasedMatcher matcher;
        vector<Mat> trainDescriptor( 1, templateEle.descriptor[eachTemplate] );
        matcher.add( trainDescriptor );
        matcher.train();
        //knn 使用underTestCellDescriptor计算eachTamplate的matchPoint
        matcher.match( underTestCellDescriptor, templateEle.descriptor[eachTemplate], matchPointVector[eachTemplate]);
        double maxDistance = 0;
        for (size_t eachPoint=0; eachPoint < matchPointVector[eachTemplate].size(); eachPoint++)
        {
            if (matchPointVector[eachTemplate][eachPoint].distance > maxDistance)
                maxDistance = matchPointVector[eachTemplate][eachPoint].distance;
        }
        for (size_t eachPoints=0; eachPoints < matchPointVector[eachTemplate].size(); eachPoints++)
        {
            if (matchPointVector[eachTemplate][eachPoints].distance <
                   0.4 * maxDistance)
            {
                goodMatchPoints[eachTemplate].push_back(
                            matchPointVector[eachTemplate][eachPoints]);
            }
        }
#ifdef DBUG
        cout << eachTemplate << " " << goodMatchPoints[eachTemplate].size() << " " << templateEle.allName[eachTemplate] << endl;
#endif
        //完成对一个模板的优秀特征点提取
        if ( (int)goodMatchPoints[eachTemplate].size() > bestMatchInfo[1] )
        {
            bestMatchInfo[0] = eachTemplate;
            bestMatchInfo[1] = goodMatchPoints[eachTemplate].size();
        }
    }
    cout << "一个元件匹配结束.." << endl;

    return bestMatchInfo;
}

int main()
{
    vector<Vec2i> bestMatchPoints(underTestEle.count, Vec2i(0 ,0));
    for ( int eachCell=0; eachCell < underTestEle.count; eachCell++ )
    {
        cout << "开始匹配第 " << eachCell << " 个元件......" << endl;
        bestMatchPoints[eachCell] = getGoodMatchUseCustom(underTestEle.descriptor[eachCell]);
    }
    for (auto eachCellInfo : bestMatchPoints)
    {

        cout << "最佳匹配编号: " << eachCellInfo[0]
             << "，器件为: " << templateEle.allName[eachCellInfo[0]]
             << ". 特征点匹配数目为: " << eachCellInfo[1] << endl;

    }
//    underTestEle.sourceImgShow();
//    underTestEle.componentImgShow();
    underTestEle.showCellAndRectImg();
    underTestEle.showLinesAndRectImg();
    underTestEle.showTextsImg();
    underTestEle.showCellsImg();

//    templateEle.allImgShow();


    waitKey(0);
    destroyAllWindows();
    return 0;
}
